package com.study.common.utils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSA非对称加密
 * <p>
 * 加密解密对应方式：
 * ① 公钥加密 -> 私钥解密
 * ② 私钥加密 -> 公钥解密
 *
 * @author nizhihao
 * @version 1.0.0
 * @date 2023/11/10 09:13
 */
public class RsaUtils {

    private static final String RSA_ECB_PADDING = "RSA/ECB/PKCS1Padding";
    private static final String RSA = "RSA";

    private static byte[] privateRsaEcb(String data,
                                        String key,
                                        int mode) throws Exception {
        byte[] dataBytes = Base64.decodeBase64(data);
        byte[] keyBytes = Base64.decodeBase64(key);
        PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);
        Cipher cipher = Cipher.getInstance(RSA_ECB_PADDING);
        cipher.init(mode, privateKey);
        return cipher.doFinal(dataBytes);
    }

    private static byte[] publicRsaEcb(String data,
                                       String key,
                                       int mode) throws Exception {
        byte[] dataBytes = Base64.decodeBase64(data);
        byte[] keyBytes = Base64.decodeBase64(key);
        X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA);
        PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);
        Cipher cipher = Cipher.getInstance(RSA_ECB_PADDING);
        cipher.init(mode, publicKey);
        return cipher.doFinal(dataBytes);
    }

    /**
     * 私钥加密
     *
     * @param encryptData 需加密数据
     * @param privateKey  私钥
     * @return 加密后数据【base64编码】
     * @throws Exception 异常
     */
    public static String privateEncrypt(String encryptData, String privateKey) throws Exception {
        byte[] bytes = privateRsaEcb(encryptData, privateKey, Cipher.ENCRYPT_MODE);
        return Base64.encodeBase64String(bytes);
    }

    /**
     * 私钥解密
     *
     * @param decryptData 需解密数据
     * @param privateKey  私钥
     * @return 解密后数据【原始字符串】
     * @throws Exception 异常
     */
    public static String privateDecrypt(String decryptData, String privateKey) throws Exception {
        byte[] bytes = privateRsaEcb(decryptData, privateKey, Cipher.DECRYPT_MODE);
        return new String(bytes, StandardCharsets.UTF_8);
    }

    /**
     * 公钥加密
     *
     * @param encryptData 需加密数据
     * @param publicKey   公钥
     * @return 加密后数据【base64编码】
     * @throws Exception 异常
     */
    public static String publicEncrypt(String encryptData, String publicKey) throws Exception {
        byte[] bytes = publicRsaEcb(encryptData, publicKey, Cipher.ENCRYPT_MODE);
        return Base64.encodeBase64String(bytes);
    }

    /**
     * 公钥解密
     *
     * @param decryptData 需解密数据
     * @param publicKey   公钥
     * @return 解密后数据【原始字符串】
     * @throws Exception 异常
     */
    public static String publicDecrypt(String decryptData, String publicKey) throws Exception {
        byte[] bytes = publicRsaEcb(decryptData, publicKey, Cipher.DECRYPT_MODE);
        return new String(bytes, StandardCharsets.UTF_8);
    }

}
